package com.sh169.filter;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.nutz.json.Json;

import com.sh169.beans.ApplicationConfig;
import com.sh169.util.ApplicationUtil;
import com.sh169.util.BaseHttpFilter;

public class SecurityFilter extends BaseHttpFilter{
	private List<Filter> filters;
	protected List<Filter> getFilters(){
		if(filters==null){
			filters = new ArrayList<Filter>();
			filters.add(new LogoutFilter());
			filters.add(new LoginPageFilter());
			filters.add(new CheckLoginFilter());
			filters.add(new IntecepterFilter());
		}
		return filters;
	}
	private static final String IGNORE = "^.+\\.(png|gif|jpg|js|css|jspx|jpeg|swf|ico)$";
	private Pattern ignorePtn;
	
	@SuppressWarnings("unchecked")
	public void init(FilterConfig arg0) throws ServletException {
		/**
		 *  解析 url-role 配置文件
		 *  格式：
		 *    {roleUrls:[{url:'/**',access:['role1','role2']},{..}]}
		 */
		InputStream is = this.getClass().getResourceAsStream("/security.js");
		Reader reader = new InputStreamReader(is);
		Map<String, Object> config = Json.fromJson(HashMap.class,reader);
		try {
			ApplicationConfig.setConfig(config);
		} catch (Exception e) {
			throw new ServletException("解析配置文件出错",e);
		}
		String path = arg0.getServletContext().getRealPath("/");
		if(path.endsWith("/")){
			path = path.substring(0,path.length()-2);
		}
		ApplicationUtil.setWebHomePath(path);
		ignorePtn = Pattern.compile(IGNORE, Pattern.CASE_INSENSITIVE);
	}
	@Override
	public void doFilter(HttpServletRequest request,
			HttpServletResponse response, FilterChain filterChain)
			throws IOException, ServletException {
		if (null!= ignorePtn && ignorePtn.matcher(request.getRequestURI()).find()) {
			filterChain.doFilter(request, response);
			return ;
		}
		List<Filter> filters = getFilters();
		if(filters==null || filters.size()==0){
			filterChain.doFilter(request, response);
			return ;
		}
		VirtualFilterChain.createVFC(filterChain, filters).doFilter(request, response);
	}
	private static class VirtualFilterChain implements FilterChain{

		private FilterChain filterChain;
		private List<Filter> filters;
		private int filterIndex = 0;

		private VirtualFilterChain(FilterChain filterChain,List<Filter> filters){
			this.filterChain = filterChain;
			this.filters = filters;
		}
		public static  VirtualFilterChain createVFC(FilterChain filterChain,List<Filter> filters){
			return new VirtualFilterChain(filterChain,filters);
		}
		public void doFilter(ServletRequest request, ServletResponse response)
				throws IOException, ServletException {
			HttpServletRequest req = (HttpServletRequest) request;
			HttpServletResponse resp = (HttpServletResponse) response;
			filterIndex++;
			if(filters.size()== filterIndex-1)
				filterChain.doFilter(req, resp);
			else{
				filters.get(filterIndex-1).doFilter(req, resp, this);
			}
		}
	}
}